package com.itheima.reggie.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.itheima.reggie.dao.CategoryDao;
import com.itheima.reggie.dao.DishDao;
import com.itheima.reggie.dao.DishFlavorDao;
import com.itheima.reggie.entity.Category;
import com.itheima.reggie.entity.Dish;
import com.itheima.reggie.entity.DishFlavor;
import com.itheima.reggie.entity.Page;
import com.itheima.reggie.entity.dto.DishDto;
import com.itheima.reggie.service.DishService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class DishServiceImpl implements DishService {

    @Autowired(required = false)
    private DishDao dishDao;
    @Autowired(required = false)
    private DishFlavorDao dishFlavorDao;
    @Autowired(required = false)
    private CategoryDao categoryDao;
    @Autowired
    private RedisTemplate redisTemplate;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void save(DishDto dishDto) {
        // 补全菜品的数据
        dishDto.setStatus(1); // 1 代表菜品是启用的 0 代表商品下架
        dishDto.setSort(0); //
        dishDto.setCreateTime(LocalDateTime.now());
        dishDto.setUpdateTime(LocalDateTime.now());
        // 保存菜品
        dishDao.save(dishDto);
        System.out.println("dishDto= "+dishDto);
        System.out.println("===================================================");
        // 添加口味
        List<DishFlavor> flavorList = dishDto.getFlavors();
        // 传统做法，给每一个口味信息补全
        for (DishFlavor dishFlavor : flavorList) {
            dishFlavor.setDishId(dishDto.getId()); // 口味对应的菜品的id
            dishFlavor.setCreateTime(dishDto.getCreateTime());
            dishFlavor.setUpdateTime(dishDto.getUpdateTime());
            dishFlavor.setUpdateUser(dishDto.getUpdateUser());
            dishFlavor.setCreateUser(dishDto.getCreateUser());
            dishFlavor.setIsDeleted(0);
        }
//        System.out.println("flavorList = " + flavorList);
        // 批量插入菜品的口味
        dishFlavorDao.batchSave(flavorList);
        // 删除缓存
        Set keys = redisTemplate.keys("dish_*");
        redisTemplate.delete(keys);
    }

    @Override
    public Page<DishDto> findByPage(Integer page, Integer pageSize, String name) {

        // 1.设置当前页与页面大小
        PageHelper.startPage(page,pageSize);
        // 2.查询页面的数据 List<Dish>
        List<Dish> dishList = dishDao.findByPage(name);
        // 4.构建一个PageInfo
        PageInfo<Dish> pageInfo = new PageInfo<>(dishList);


        // 3.把List<Dish>转换为List<DishDto>
       /* List<DishDto> dishDtoList = new ArrayList<>();
        for (Dish dish : dishList) {
            DishDto dishDto = new DishDto();
            // 如果两个实体类的属性名和类型都一致的情况下，我们可以可以使用spring提供的工具类
            BeanUtils.copyProperties(dish,dishDto);
            // 根据菜品的类别id查询类别
            Category category = categoryDao.findById(dish.getCategoryId());
            dishDto.setCategoryName(category.getName());
            dishDtoList.add(dishDto);
        }*/


        // 使用jdk8的Stream流 Stream流的作用：简化集合与数组的操作 map方法
        List<DishDto> dishDtoList = dishList.stream().map(dish -> {
            DishDto dishDto = new DishDto();
            // 如果两个实体类的属性名和类型都一致的情况下，我们可以可以使用spring提供的工具类
            BeanUtils.copyProperties(dish,dishDto);
            // 根据菜品的类别id查询类别
            Category category = categoryDao.findById(dish.getCategoryId());
            dishDto.setCategoryName(category.getName());
            return dishDto;
        }).collect(Collectors.toList());


        // 5.把PageInfo转换为Page对象
        Page<DishDto> pageResult  = new Page<>();
        pageResult.setRecords(dishDtoList);
        pageResult.setTotal(pageInfo.getTotal());
        pageResult.setPageSize(pageInfo.getPageSize());
        pageResult.setPage(pageInfo.getPageNum());

        return pageResult;
    }

    @Override
    public DishDto findById(Long id) {
        // 1.根据菜品的id查询菜品信息
        Dish dish = dishDao.findById(id);
        // 2.根据菜品的id查询菜品对应口味的信息
        List<DishFlavor> dishFlavorList = dishFlavorDao.findByDishId(id);
        // 3.把菜品信息与口味信息封装成DishDto
        DishDto dishDto = new DishDto();
        // 属性拷贝 源
        BeanUtils.copyProperties(dish,dishDto);
        // 设置口味信息
        dishDto.setFlavors(dishFlavorList);
        return dishDto;
    }

    @Transactional
    @Override
    public void updateDish(DishDto dishDto) {
        // 1. 更新时间
        dishDto.setUpdateTime(LocalDateTime.now());
        // 2. 更新菜品
        dishDao.updateDish(dishDto);
        // 3. 删除菜品口味
        dishFlavorDao.deleteByDishId(dishDto.getId());
        // 4. 得到当前菜品最新口味，然后补全数据
        List<DishFlavor> flavorList = dishDto.getFlavors();
        // 传统做法，给每一个口味信息补全
        for (DishFlavor dishFlavor : flavorList) {
            dishFlavor.setDishId(dishDto.getId()); // 口味对应的菜品的id
            dishFlavor.setCreateTime(dishDto.getCreateTime());
            dishFlavor.setUpdateTime(dishDto.getUpdateTime());
            dishFlavor.setUpdateUser(dishDto.getUpdateUser());
            dishFlavor.setCreateUser(dishDto.getCreateUser());
            dishFlavor.setIsDeleted(0);
        }
        // 5. 批量插入口味信息
        dishFlavorDao.batchSave(flavorList);
    }

    /*
        使用缓存思想：
            1.请求过来获取数据的时候先问redis获取
            2.如果redis有数据，直接从redis中返回
            3.如果redis没有数据，查询数据库，返回的结果存储到redis中
     */

    @Override
    public List<DishDto> list(Long categoryId, Integer status) {
        List<DishDto> dishDtoList = null;
        ValueOperations valueOperations = redisTemplate.opsForValue();

        String key = "dish_"+categoryId+"_"+status;
        if (valueOperations.get(key)!=null){
            dishDtoList = (List<DishDto>) valueOperations.get(key);
        }else {
            // 如果redis中没有对应的缓存数据，那么直接查询数据库，然后把查询的数据库保存给redis
            List<Dish> dishList = dishDao.findByCategoryId(categoryId,status);
            dishDtoList = dishList.stream().map(dish -> {
                DishDto dishDto = new DishDto();
                BeanUtils.copyProperties(dish, dishDto);
                // 查询菜品对应的口味
                List<DishFlavor> flavorList = dishFlavorDao.findByDishId(dish.getId());
                dishDto.setFlavors(flavorList);
                return dishDto;
            }).collect(Collectors.toList());
            valueOperations.set(key,dishDtoList,24, TimeUnit.MINUTES);
        }


        return dishDtoList;
    }
}
